# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
# 
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
# Author: Michael DiBernardo (mikedebo@gmail.com)
# Copyright Michael DiBernardo 2009

"""
A test case that can test all the basic functionality that is shared across
tickers.
"""
import datetime
from tikk.core.test.integration.test_utils import TikkIntegrationTestCase
from tikk.core.models import *
import tikk.core.injectibles as injectibles

class BaseTickerUsageTestCase(TikkIntegrationTestCase):

    def setUp(self):
        # Number of times the tickCreationTest method has been called. We use
        # this to generate assertions against how many ticks we expect there to
        # be in the database.
        self.numTickCreationTesterCalls = 0
        injectibles.timestamp = lambda: datetime.datetime.now()

    def tickCreationTester(self, ticker_type, extra_args_url, create_ticker=True):
        """
        Given the ticker type and the extra args that go to the ticker when you
        record a new tick (as an url my/extra/args/), tests that you can create
        such a tick and that the base values are correct.

        Returns the single created tick so that you can do more checking on it
        if you wish.
        """
        self.numTickCreationTesterCalls += 1

        # Create the ticker we need.
        if (create_ticker):
            self.getUrlAndAssertStatusCode('/create/%s/myticker/' % ticker_type, 200)

        # The datetime that we'll take as the expected value and inject into
        # the timestamper.
        expected_timestamp = datetime.datetime.now()

        # Inject the timestamper.
        injectibles.timestamp = lambda: expected_timestamp

        # Register an event.
        self.getUrlAndAssertStatusCode(
                '/%s/myid/myticker/%s' % (ticker_type, extra_args_url), 200)

        # We should have a tick in the database now.
        myticker = Ticker.objects.get(name__exact="myticker")
        self.assertEquals(self.numTickCreationTesterCalls, myticker.tick_set.count())

        tick = myticker.tick_set.order_by("-timestamp")[0]

        self.assertEquals(expected_timestamp, tick.timestamp)
        self.assertEquals("myid", tick.identity)

        return tick

    def tickDoesntExistTester(self, ticker_type, extra_args_url):
        """
        If you send a ping to a ticker that hasn't been created, you should get
        a 404.
        """
        self.getUrlAndAssertStatusCode(
                '/%s/myid/sometikker/%s' % (ticker_type, extra_args_url), 404)
        self.assertEquals(0, Tick.objects.count())

    def repeatedlyHitACoupleOfTickersTest(self, ticker_type, extra_args_url):
        """
        Small use case where we're hitting a couple of tickers. The
        extra_args_url here will be applied to every hit on both tickers.
        """
        self.getUrlAndAssertStatusCode('/create/%s/ticker1/' % ticker_type, 200)
        self.getUrlAndAssertStatusCode('/create/%s/ticker2/' % ticker_type, 200)
        
        ping_order = [1, 2, 2, 1, 2]
        num_first_pings = len(filter(lambda x: x == 1, ping_order))
        num_second_pings = len(filter(lambda x: x == 2, ping_order))

        for ticker_index in ping_order:
            self.getUrlAndAssertStatusCode(
                    '/%s/myid/ticker%d/%s' % (ticker_type, ticker_index, extra_args_url), 200)

        self.assertEquals(num_first_pings,
            Ticker.objects.get(name__exact="ticker1").tick_set.count())
        self.assertEquals(num_second_pings,
            Ticker.objects.get(name__exact="ticker2").tick_set.count())
